Descrição da página

Este projeto buscou dados encontrados na página da Câmara Municipal do Rio de Janeiro http://www.camara.rj.gov.br/.

Esta página disponibiliza diversas informações a respeito da produção e atividade dos veradores da cidade. Ela é atualizada sempre que necessário com todos os materiais das atividades das Sessões Plenárias.

A escolha desta página para análise foi motivada pela falta de recursos facilmente acessíveis para que a população acompanhe um resumo da atividade parlamentar do município do Rio de Janeiro.

As informações aqui apresentadas se referem à 10ª Legislatura, que compreende o os anos de 2017 a 2020.

Será apresentada a composição atual da Câmara Municipal, a frequência dos parlamentares e as atividades realizadas durante este período.

Em relação à atividade parlamentar, buscou-se informações a respeito de Projetos de Emenda à Lei Orgânica, Projetos de Lei Complementar, Projetos de Lei, Projetos de Decreto Legislativo, Projetos de Resolução, Indicações, Moções, Requerimentos de Informação e Requerimentos e Ofícios. Também foram coletadas as Leis Complementares e Emendas à Lei Orgânica que entraram em vigor no período especificado.

Fluxo do webscrapping

Em geral, todas as páginas coletadas para as Matérias Legislativas e Legislação Municipal apresentaram uma estrutura similar. Para exemplificar, irei apresentar a raspagem feita na página de Projetos de Lei.

O site oferece as informações organizadas por número, por ano, ou por autor. Como o interesse do projeto é buscar os dados por ano, para facilitar a filtragem do material desejado a raspagem foi realizada pela aba POR ANO para a maioria das matérias legislativas, excetuando-se algumas que apresentaram uma estrutura diferente das demais.

As páginas puderam ser acessadas com uma simples requisição GET para a url e os parâmetros de query para a página desejada. A página principal de exibição dos resultados não nos mostra todos, sendo necessário ir clicando em “próximo” até se obter todos os resultados do ano desejado.

Carregando os pacotes necessários

library(tidyverse)
library(rvest)
library(httr)
library(lubridate)
library(knitr)
library(kableExtra)
library(highcharter)

Headers de requisição

  u_base <- "https://mail.camara.rj.gov.br/APL/Legislativos/scpro1720.nsf/Internet/LeiEmentaInt"
  q_base <- list(
    "OpenForm" = "",
    "Start" = 1,   # Número da página atual.
    "Count" = 100, # Quantidade de resultados apresentados na página.
    "Expand" = 1   # Índice do ano (Se descendente, 1 para 2020, 2 para 2019...)
  )
  get_materia <- GET(u_base, query = q_base)

O valor de Start para a troca de página segue uma lógica pouco intuitiva. No exemplo acima, a primeira página começa em 1, a seguinte é 1.99, depois 1.198, 1.297, 1.396, acrescentando 1 após o decimal e diminuindo 1 do último número. Para contornar este problema, optei por modificar o valor de Count para 1000, já que assim conseguiria que a página me retornasse todos os resultados. Verificando que nenhuma ano retornava mais do que 1000 resultados, esta solução foi suficiente para obter os dados desejados, embora não seja a ideal.

Raspagem dos dados

Matérias Legislativas e Legislação Municipal

As informações a respeito dos Projetos de Lei e demais matérias são apresentadas no formato de tabela. Assim, foi feita uma leitura do html da página por meio da função xml2::read_html(get_materia), seguida de uma busca por todas as tabelas com xml2::xml_find_all('//table').

Obtida a tabela, renomeio as colunas para um formato mais fácil de leitura e manipulação com janitor::clean_names(). Seleciono então apenas as colunas com informações relevantes, descartando as outras “extra” vazias, renomeio-as novamente para nomes mais amigáveis e a transformo com as_tibble().

Os nomes dos autores dos projetos são, em grande maioria, separados por ,. No entanto, ainda há alguns nomes separados por “E” e outras formas e que devem ser corrigidos (ainda não foi feita esta correção neste projeto),

Na coluna ementa há linhas com NA e valores do ano que não correspondem à observações com informações. A filtragem com str_detect() as elimina.

Por fim, a coluna com a data de publicação é transformada em date, a ementa é “limpa” de caracteres “estranhos” com um str_squish(), o nome dos atuores tem a primeira letra capitalizada com str_to_title() para uniformizar entre todos os dataframes relacionados e é retirado o título "Vereador/ Vereadora da frente do nome do parlamentar com str_remove(autores, "(Vereador)(a*) "), também importante para se utilizar com outros dataframes relacionados.

read_html(get_materia) %>%  # lê o html da página
    xml_find_all('//table') %>% # busca os nodes do tipo table
    magrittr::extract2(2) %>%   # extrai o segundo node, que contém a tabela principal
    html_table(fill = TRUE) %>% # leitura da tabela
    janitor::clean_names() %>%  
    select(c("x_2", "ementa", "data_publ", "autor_es")) %>% # 
    set_names(c("prolei_num", "ementa", "data_publi", "autores")) %>% 
    as_tibble() %>% 
    separate_rows(autores, sep = ",") %>% 
    filter(str_detect(ementa, "^[A-Z]")) %>%
    mutate(data_publi = mdy(data_publi), 
           ementa = str_squish(ementa),  
           autores = str_to_title(autores), 
           autores = str_remove(autores, "(Vereador)(a*) ")) 

Esta tabela apresentará a seguinte composição:

read_rds("out/prolei.rds") %>% glimpse(.)
## Rows: 3,917
## Columns: 5
## $ prolei_num <chr> "2014/2020", "2013/2020", "2012/2020", "2011/2020", "201...
## $ ementa     <chr> "CRIA O SELO DE RESPONSABILIDADE SOCIAL \"PARCEIROS DAS ...
## $ data_publi <date> 2020-12-04, 2020-12-03, 2020-12-03, 2020-12-03, 2020-12...
## $ autores    <chr> "Veronica Costa", "Carlos Bolsonaro", "Carlos Bolsonaro"...
## $ materia    <chr> "Projeto de Lei", "Projeto de Lei", "Projeto de Lei", "P...
  • A coluna prolei_num apresenta o número do Projeto de Lei
  • A coluna ementa apresenta a ementa da proposta
  • A coluna data_publi apresenta a data de publicação do projeto
  • A coluna autores apresenta por linha cada autor do projeto
  • A coluna materia é adicionada posteriormente na função que coleta os dados, e apresenta o tipo de matéria. Será útil quando os dataframes com todas as matérias forem unificados

Exceções: Projeto de Decreto Legislativo e Projeto de Resolução

Para estas duas categorias foi necessário extrair os dados a partir da aba POR NÚMERO. Para o Projetos de Decreto Legislativo a aba POR ANO não retornava o nome do(s) autor(es) e para o Projeto de Resolução, o site direciona para a página de Projetos de Lei. O modo de requisição dos dados foi basicamente o mesmo. Sendo alterada apenas a iteração das páginas para Start ao invés de Expand. Como são poucas páginas com resultados, coletei manualmente os valores de Expand para cada página. Outra solução que precisa de melhor refinamento para não “quebrar” posteriormente.

Vereadores Atuais

Os resultados da página de vereadores atuais também estão dispostos no formato table, exigindo apenas uma busca para nodes deste tipo. No entanto, a foto e o partido dos vereadores não são retornados na tabela principal, necessitando que fossem buscados de forma separada por meio da classe e fossem extraídas as informações desejadas contidas nos atributos

u_ver <- "http://www.camara.rj.gov.br/vereadores_atuais.php?m1=vereadores&m2=ver_atuais&m3=por_nome"

partidos <- read_html(u_ver) %>% 
  xml_find_all("//td[@class='td3']//img") %>% 
  xml_attr("title") %>% 
  str_squish()

foto_vereador <- read_html(u_ver) %>% 
  xml_find_all("//td[@class='td3']//img") %>% 
  xml_attr("src")

vereadores <- read_html(u_ver) %>% 
  xml_find_first('//table') %>% 
  html_table(header = TRUE) %>% 
  janitor::clean_names() %>% 
  as_tibble() %>% 
  mutate(partido = partidos,
         foto = foto_vereador,
         vereador = str_to_title(vereador),
         foto = str_replace_all(foto, " ", "%20")) # troca espaço vazio consertando um link com este problema)

Este dataframe apresentará a seguinte composição:

read_rds("out/vereadores.rds") %>% glimpse(.)
## Rows: 51
## Columns: 6
## $ foto     <chr> "http://www.camara.rj.gov.br/images/foto_vereador/alexandr...
## $ vereador <chr> "Alexandre Isquierdo", "Átila A. Nunes", "Babá", "Carlo Ca...
## $ partido  <chr> "DEM", "DEM", "PSOL", "DEM", "REPUBLICANOS", "DEM", "PODE"...
## $ sala     <chr> "Anexo 803", "Anexo 706", "Anexo 903", "Anexo 1003", "Anex...
## $ telefone <chr> "3814-2406/2200/2220", "3814-2136 / 2139 / 2010", "3814-24...
## $ e_mail   <chr> "alexandreisquierdo@camara.rj.gov.br", "atila.nunes@camara...
  • A coluna foto contém o link para foto do(a) verador(a)
  • A coluna vereador contém o nome do(a) verador(a)
  • A coluna partido contém o partido do(a) verador(a)
  • A coluna sala contém o número da sala do(a) verador(a)
  • A coluna telefone contém os números de telefone do(a) verador(a)
  • A coluna e_mail contém o email do(a) verador(a)

Frequência dos veradores

A página de frequência dos vereadores é a que se diferencia um pouco mais das anteriores. Ela solicita uma requisição POST e os parâmetros de consulta são definidos em Request, em que os parâmetros variáveis são "ano" e "mes".

Obtida a página, os resultados são apresentados no formato de tabela, assim como nas demais. No entanto, o nome das colunas não é retornado na tabela obtida, sendo necessário buscá-los por meio da classe dos nodes: xml_find_all("//td[contains(@class, 'azul-claro')]

# url base
  u <- "http://www.camara.rj.gov.br/vereadores_frequencia.php?m1=materias_leg&m2=freq"

# Parâmetros do corpo da requisição
  b <- list(
        "ano" = ano, # definido de forma numérica
        "mes" = paste0(n_mes, "|", mes), # utiliza o formato (número do mês)|(nome do mês), por exemplo: "2|Fevereiro"
        "sessao" = 1, # não muda
        "submit" = "Consultar" # não muda; realiza a consulta
    )

    r <- POST(u, body = b)
    t <- read_html(r) %>% 
        xml_find_first('//table') %>% 
        html_table(fill = TRUE)
    faltas <- t %>% 
            as_tibble() %>% 
            set_names(xml_find_all(
                read_html(r), 
                    "//td[contains(@class, 'azul-claro')]") %>% # busca pelo título
                    html_text() %>%     # das colunas, extrai o texto e "limpa" com
                    str_squish()        # o str_squish()
                ) %>% 
            janitor::clean_names() %>%  
            slice(-1) %>%  # elimina a primeira linha que não contém informações
            mutate(ano = ano, # cria uma coluna com o ano da consulta
                   nome_mes = str_to_lower(mes), # coluna com o nome do mes da consulta e passa para lowercase
                   mes = n_mes, # coluna com o numero do mes da consulta
                   faltas = as.double(faltas), 
                   faltas_abonadas = as.double(faltas_abonadas),
                   total_de_faltas = as.double(total_de_faltas))
        # por fim, transforma as colunas com o numero de faltas em double

Um função é aplicada coletando as faltas de todos os meses para cada ano (2017-2020) e posteriormente são unificadas em uma base de dados.

Este dataframe apresentará a seguinte composição:

read_rds("out/df_faltas.rds") %>% glimpse(.)
## Rows: 1,753
## Columns: 7
## $ vereador        <chr> "Alexandre Arraes", "Alexandre Isquierdo", "Carlo C...
## $ faltas          <dbl> 0, 0, 0, 0, 1, 3, 1, 0, 1, 1, 1, 0, 0, 2, 0, 0, 0, ...
## $ faltas_abonadas <dbl> 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, ...
## $ total_de_faltas <dbl> 0, 0, 0, 0, 0, 3, 1, 0, 1, 1, 0, 0, 0, 2, 0, 0, 0, ...
## $ ano             <dbl> 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 201...
## $ nome_mes        <chr> "fevereiro", "fevereiro", "fevereiro", "fevereiro",...
## $ mes             <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ...
  • A coluna vereador contém o nome do(a) verador(a)
  • A coluna faltas contém as faltas totais do(a) verador(a)
  • A coluna faltas_abonadas contém as faltas abonadas do(a) verador(a)
  • A coluna total_de_faltas contém as faltas totais, descontadas as abonadas
  • A coluna ano especifica o ano da falta observada
  • A coluna nome_mes especifica o nome do mês da falta observada
  • A coluna mes especifica o número do mês da falta observada

Apresentação dos dados

Vereadores atuais (2017-2020)

A tabela abaixo apresenta os parlamentares em atividade no período de 2017 a 2020. Não estão presentes vereadores(as) afastados(as) ou substtuídos(as).

vereadores <- read_rds("out/vereadores.rds")

vereadores %>% 
    mutate(foto = "") %>% 
    kbl(align = "c") %>% 
    column_spec(1, image =  spec_image(vereadores$foto, 
                                       width = 180, height = 150)) %>% 
    kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                  full_width = TRUE) %>% 
    scroll_box(width = "100%", height = "500px")
foto vereador partido sala telefone e_mail
Alexandre Isquierdo DEM Anexo 803 3814-2406/2200/2220
Átila A. Nunes DEM Anexo 706 3814-2136 / 2139 / 2010
Babá PSOL Anexo 903 3814-2429
Carlo Caiado DEM Anexo 1003 3814-2081 a 2083/2513/2514
Carlos Bolsonaro REPUBLICANOS Anexo 905 3814-2117 a 2119 /2717
Cesar Maia DEM Palácio 31-B 3814-2331/2735/2485/2492/2592/2484/2476
Dr. Carlos Eduardo PODE Palácio 32-B 3814-2328/2434/2490/2773/2469/2491
Dr. Gilberto PTC Palácio 38-B 3814-2131 / 2133 / 2134
Dr. Jairinho SOLIDARIEDADE Anexo 406 3814-2147 / 2218 / 2296 / 2375 / 2376
Dr. João Ricardo PSC Anexo 802 3814-2246 / 2944 / 2418
Dr. Jorge Manaia PROGRESSISTAS Anexo 801 3814-2140/2143/2144/2563
Dr. Marcos Paulo PSOL Anexo 702 3814-2441 / 2444 / 2935
Eliseu Kessler PSD Anexo 904 3814-2102/2103/2105 /2050
Fátima Da Solidariedade SOLIDARIEDADE Anexo 701 3814-2176 / 2238
Felipe Michel PROGRESSISTAS Anexo 705 3814-2069/2749/2901/2903/2905/
Fernando William PDT Anexo 1005 3814-2011/2157/2531/2543
Inaldo Silva REPUBLICANOS Anexo 501 3814-2607/2609/2178
Italo Ciba AVANTE Anexo 1004 3814-2158/2159/2162/2270 e 2034
Jair Da Mendes Gomes PROS Anexo 305 3814-2231/2232/2456/2457
João Mendes De Jesus REPUBLICANOS Anexo 306 3814-2009 / 2057 / 2061 / 2333
Jones Moura PSD Anexo 804 3814-2570/2571
Jorge Felippe DEM Anexo 505 3814-2001 a 2004 / 2271
Junior Da Lucinha PL Anexo 901 3814-2451/2455/2500/2669
Leandro Lyra REPUBLICANOS Anexo 601 3814-2088/2089/2091
Leonel Brizola PSOL Anexo 806 3814-2125/2180/2412
Luciana Novaes PT Palácio 14-A 3814-2511 e 2598.
Luiz Carlos Ramos Filho PMN Anexo 504 3814-2005 / 2007 / 2387
Major Elitusalem PSC Anexo 604 3814-2498 / 2585 / 2237 / 2475 / 2043
Marcelino D Almeida PROGRESSISTAS Anexo 602 3814-2183 a 2185/2448/2515
Marcello Siciliano PROGRESSISTAS Anexo 401 3814-2073/2179/2722
Marcelo Arar PTB Anexo 506 3814-2030/2045/2046
Paulo Messina MDB Anexo 404 3814-2545
Paulo Pinheiro PSOL Anexo 1002 3814-2393/2068/2920/2463
Prof.célio Lupparelli DEM Anexo 906 3814-2036 à 2038 /2746/2760/2072
Professor Adalmir PROGRESSISTAS Anexo 1006 3814-2086/2087/2170/2365
Rafael Aloisio Freitas CIDADANIA Anexo 403 3814-2024
Reimont PT Anexo 302 3814-2113 a 2115 / 2394
Renato Cinco PSOL Anexo 503 3814-2026 a 2029 / 2008
Renato Moura PATRIOTA Anexo 303 3814-2401/2461/2446/2449
Rocal PSD Anexo 402 3814-2127 / 2128 / 2131 / 2442
Rosa Fernandes PSC Anexo 304 3814-2065 a 2067/2255
Tânia Bastos REPUBLICANOS Anexo 301 3814-2097 a 2099/2512
Tarcísio Motta PSOL Anexo 902 3814-2330/2051
Teresa Bergher CIDADANIA Anexo 405 3814-2053/ 2054/ 2055/ 2056/ 2229/ 2389/ 2391
Thiago K. Ribeiro DEM Anexo 1001 3814-2381/2383/2384
Vera Lins PROGRESSISTAS Anexo 606 3814-2187/2587/2579/2433
Veronica Costa DEM Anexo 605 3814-2580 / 2590
Welington Dias PDT Anexo 502 3814-2070 / 2094 / 2497 /
Willian Coelho DC Anexo 603 3814-2154 a 2156
Zico REPUBLICANOS Anexo 805 3814-2167 a 2169/2172
Zico Bacana PODE Anexo 703 3814-2017 / 2078 / 2018 / 2019
vereadores %>% 
    count(partido) %>% 
    mutate(prop = n/sum(n)) %>% 
    hchart("treemap",
           hcaes(x = partido, value = n, color = prop)) %>% 
    hc_title(text = "Composição da Câmara Municipal por partido",
             style = list(fontWeight = "bold", fontSize = "25px"),
             align = "center"
    )

Atividade Parlamentar

Nesta tabela é possível explorar todos a atividade dos(as) vereadore(as) registradas durante o período da 10ª Legislatura, entre Projetos de Emenda à Lei Orgânica, Projetos de Lei Complementar, Projetos de Lei, Projetos de Decreto Legislativo, Projetos de Resolução, Indicações, Moções, Requerimentos de Informação e Requerimentos e Ofícios.

library(reactable)
atvp <- read_rds("out/atv_parlam.rds")
atvp <- atvp %>% 
    select(-c(foto, sala, telefone, e_mail)) %>% 
    mutate(ementa = str_to_lower(ementa),
           ementa = str_remove(ementa, " =.*"),
           data_publi = format(data_publi, format = '%d/%m/%Y'))
reactable(atvp, filterable = TRUE, columns = list(
    prolei_num = colDef(name = "Nº do Projeto"),
    data_publi = colDef(name = "Data de publicação"),
    autores = colDef(name = "Autores"),
    materia = colDef(name = "Matéria"),
    partido = colDef(name = "Partido"),
    ementa = colDef(name = "Ementa")))

Frequência dos Vereadores

O gráfico mostra o número total de faltas não abonadas por vereador(a).

faltas <- read_rds("out/df_faltas.rds")
vereadores <- read_rds("out/vereadores.rds")

plot(faltas %>% 
    left_join(vereadores, by = "vereador") %>% 
    filter(!is.na(partido)) %>% 
    mutate(vereador = str_c(vereador," " ,"(", partido, ")")) %>% 
    group_by(vereador) %>% 
    summarise(n_faltas = sum(total_de_faltas), .groups = "drop") %>% 
    mutate(vereador = fct_reorder(vereador, n_faltas)) %>% 
    ggplot(aes(x = n_faltas, y  = vereador)) + 
    geom_col(fill = "darkred") +
    theme_minimal(12) +
    labs(y = "", x = "", 
         title = "Número de faltas não abonadas no período 2017-2020"))

Volume de atividade por mês

Este gráfico apresenta o volume de atividade registrado mensalmente e separado por ano. O volume de processos representa qualquer atividade registrada considerando-se as matérias legislativas coletadas.

read_rds("out/atv_parlam.rds") %>% 
    select(-c(foto, sala, telefone, e_mail)) %>% 
    mutate(mes = month(data_publi, label = TRUE),
           ano = year(data_publi),
           id = group_indices(., prolei_num, materia)) %>% 
    filter(!is.na(mes), 
           !is.na(ano),
           ano >= 2017) %>% 
    group_by(mes, ano) %>%
    summarise(n = n_distinct(id), .groups = "drop") %>% 
    mutate(ano = as_factor(ano)) %>% 
    ggplot(aes(x = mes, y = n, group=factor(ano), colour=factor(ano))) +
    geom_line(size = 0.8) +
    theme_minimal(12) +
    labs(colour = "Ano",
         y = "Volume de processos", x = "")

Relatório de Produção Legislativa

Para esta análise, foi somado o número de participações de cada vereador(a) em Projetos de Lei e Projetos de Lei Complementares, formando a categoria das Propostas. A categoria Em vigor, foi obtida de forma semelhante, com a soma da participação de cada vereador em Leis Ordinárias e Leis Complementares em vigor a partir de 2017.

Os vereadores estão ordenados no gráfico em ordem decrescente pela proporção de participação em Projetos de Lei propostos e em vigor.

Um projeto que não tenha entrado em vigor não significa que necessariamente tenha sido vetado. Muitos ainda estão em discussão.

# Foi observado um conflito devido à não acentuação de alguns nomes de vereadores 
# na base de dados das Leis Ordinárias e Complementares.
# A função abjutils::rm_accent() foi utilizada para uniformizar os nomes das bases relacionadas.

lmp <- read_rds("out/l_muni.rds")

# A base de dados dos vereadores é carregada para retirar da análise das leis e 
# projetos vereadores não ativos atualmente.
vereadores <- vereadores %>% 
    mutate(vereador = abjutils::rm_accent(vereador))%>% 
    select(-c(foto, sala, telefone, e_mail))

# Carrega a base com as Leis em vigor e soma todas as observações por candidato
em_vigor <- lmp %>% 
    mutate(autoria = abjutils::rm_accent(autoria)) %>% 
    filter(autoria %in% vereadores$vereador) %>% 
    group_by(autoria) %>% 
    summarise(n_vigor = n_distinct(id), .groups = "drop")

# salva em um novo objeto somente as observações com as matérias de interesse
projeto <- atvp %>% 
    mutate(autores = abjutils::rm_accent(autores)) %>% 
    filter(autores %in% vereadores$vereador) %>%
    filter(materia %in% c("Projeto de Lei", "Projeto de Lei Complementar")) %>% 
    mutate(id = group_indices(., prolei_num, materia)) %>% 
    group_by(autores) %>% 
    summarise(n_projetos = n_distinct(id), .groups = "drop")

# Construção do gráfico
projeto %>% 
    left_join(em_vigor, c("autores" = "autoria")) %>% 
    left_join(vereadores, c("autores" = "vereador")) %>% 
    mutate(autores = str_c(autores," " ,"(", partido, ")")) %>% 
    mutate(prop_aprv = n_vigor/n_projetos) %>% 
    mutate(autores = fct_reorder(autores, prop_aprv)) %>% 
    ggplot() + 
    geom_col(aes(x = n_projetos, y = autores, fill = "Projetos de Lei apresentados")) +
    geom_col(aes(x = n_vigor, y = autores, fill = "Lei em vigor")) +
    scale_fill_manual(name="", values=c("#566573", "#D6EAF8"))+
      theme_classic(12) +
    theme(legend.position="top") +
      ggtitle("Participação em Projetos de Lei propostos e aprovados") +
      labs(x = "Número de Leis", y ="")